package com.ysstech.activiti.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import com.ysstech.activiti.model.CommentEntity;
import com.ysstech.activiti.model.TaskEntity;
import com.ysstech.activiti.service.ActivitiTaskService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class ActivitiTaskServiceImpl implements ActivitiTaskService {
    @Autowired
    private TaskService taskService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private IdentityService identityService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private RepositoryService repositoryService;

    /**
     * 查询需要自己审批
     *
     * @param userId
     * @return
     */
    public Map<String, Object> querApprovalFlow(String userId) throws Exception {
        // 已签收和未签收同时查询
        List<Task> taskList = taskService.createTaskQuery()
                // .taskAssignee(name)//指定个人任务查询
                .taskCandidateOrAssigned(userId)
                .orderByTaskCreateTime().desc().list();
        Long count = taskService.createTaskQuery()
                // .taskAssignee(name)//指定个人任务查询
                .taskCandidateOrAssigned(userId)//查询组用户
                .orderByTaskCreateTime().desc().count();
        List<TaskEntity> taskEntityList = new ArrayList<>();
        for (Task task : taskList) {
            TaskEntity taskEntity = new TaskEntity();
            taskEntity.setParentTaskId(task.getProcessDefinitionId());
            //流程的发起人
            String startUserId = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId()).singleResult().getStartUserId();//获取发起人
            taskEntity.setAssignee(startUserId);
            taskEntity.setCategory(task.getCategory());
            taskEntity.setDescription(task.getDescription());
            taskEntity.setCreateTime(task.getCreateTime().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime());
            taskEntity.setName(task.getName());
            taskEntity.setTenantId(task.getId());
            taskEntityList.add(taskEntity);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("rows", taskEntityList);
        map.put("total", count);
        return map;
    }


    /**
     * 审核流程
     *
     * @param userId  审核人
     * @param outcome （通过还是驳回）
     * @param taskId  任务ID
     * @param message 批注信息
     * @return
     * @throws Exception
     */
    public void approvalFlow(String userId, String outcome, String taskId, String message) throws Exception {
        //使用任务ID，查询任务对象，获取流程流程实例ID
        Task task = taskService.createTaskQuery()//
                .taskId(taskId)//使用任务ID查询
                .singleResult();
        String startUserId = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId()).singleResult().getStartUserId();//获取发起人
        if (!userId.equals(startUserId)) { //不是登录人自自己才去添加审核信息
            //获取流程实例ID
            String processInstanceId = task.getProcessInstanceId();
            identityService.setAuthenticatedUserId(userId);
            taskService.addComment(taskId, processInstanceId, message);
        }
        Map<String, Object> variables = new HashMap<>();
        if (StringUtils.isNotBlank(outcome)) {
            variables.put("isPass", outcome);
        }
        //3：使用任务ID，完成当前人的个人任务，同时流程变量
        taskService.complete(taskId, variables);
    }

    /**
     * 驳回流程
     *
     * @param task
     * @param processInstanceId
     * @param message
     */
    private void commitProcess(Task task, String processInstanceId, String message) {
        Map<String, Object> variables = new HashMap<>();
        //获取当前节点Id
        String currentActivityId = task.getTaskDefinitionKey();
        //获取模型实体
        String processDefinitionId = task.getProcessDefinitionId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        //获取当前节点
        FlowElement currentFlow = bpmnModel.getFlowElement(currentActivityId);
        //获取目标节点
        FlowElement targetFlow = bpmnModel.getFlowElement(processInstanceId);
        //创建连线
        String uuid = UUID.randomUUID().toString().replace("-", "");
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId(uuid);
        newSequenceFlow.setSourceFlowElement(currentFlow);
        newSequenceFlow.setTargetFlowElement(targetFlow);
        //设置条件
        newSequenceFlow.setConditionExpression("${\"+uuid+\"==\"" + uuid + "\"}");
        //添加连线至bpmn
        bpmnModel.getMainProcess().addFlowElement(newSequenceFlow);
        //添加变量（保证这根线独一无二）
        variables.clear();//清空变量，防止干扰
        variables.put(uuid, uuid);
        //提交
        taskService.addComment(task.getId(), task.getProcessInstanceId(), message);
        //完成任务
        taskService.complete(task.getId(), variables);
        //删除连线
        bpmnModel.getMainProcess().removeFlowElement(uuid);
    }


    /**
     * 通过taskId查询objId
     *
     * @param taskId
     * @return
     */
    public Map<String, Object> queryObjId(String taskId) throws Exception {
        Map<String, Object> map = new HashMap<>();
        //1：使用任务ID，查询任务对象Task
        Task task = taskService.createTaskQuery()//
                .taskId(taskId)//使用任务ID查询
                .singleResult();
        //2：使用任务对象Task获取流程实例ID
        String processInstanceId = task.getProcessInstanceId();
        //3：使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        ProcessInstance pi = runtimeService.createProcessInstanceQuery()//
                .processInstanceId(processInstanceId)//使用流程实例ID查询
                .singleResult();
        map.put("key", pi.getProcessDefinitionKey());
        //4：使用流程实例对象获取BUSINESS_KEY
        String buniness_key = pi.getBusinessKey();
        //5：获取BUSINESS_KEY对应的主键ID，使用主键ID，查询请假单对象（LeaveBill.1）
        String objId = "";
        if (org.apache.commons.lang.StringUtils.isNotBlank(buniness_key)) {
            //截取字符串，取buniness_key小数点的第2个值
            objId = buniness_key.split("\\.")[1];
        }
        map.put("objId", objId);
        return map;
    }


    /**
     * 使用任务ID，获取当前任务节点中对应的Form key中的连接的值
     */
    @Override
    public String queryTaskFormKeyByTaskId(String taskId) throws Exception {
        FormService formService = processEngine.getFormService();
        TaskFormData formData = formService.getTaskFormData(taskId);
        //获取Form key的值
        String url = formData.getFormKey();
        return url;
    }


    /**
     * 通过taskId，查询历史批注信息
     *
     * @param taskId
     * @return
     */
    public List<CommentEntity> queryCommentByTaskId(String taskId) {
        Task task = taskService.createTaskQuery()//
                .taskId(taskId)//使用任务ID查询
                .singleResult();
        String processInstanceId = task.getProcessInstanceId();  //获取流程实例ID
        List<Comment> list = taskService.getProcessInstanceComments(processInstanceId);
        List<CommentEntity> commentEntityList = new ArrayList<>();
        for (Comment comment : list) { //审批信息
            CommentEntity commentEntity = new CommentEntity();
            commentEntity.setUserId(comment.getUserId());
            commentEntity.setDatetime(LocalDateTime.now());
            commentEntity.setMsg(comment.getFullMessage());
            commentEntityList.add(commentEntity);
        }
        return commentEntityList;
    }

}
